using System;
using System.Collections.Generic;
using System.Linq;
using Sustainalytics.CRT.Synchronization.Entities;
using Sustainalytics.ESG.Entities;

namespace Sustainalytics.CRT.Synchronization
{
    public class MarketCapitalizationManager
    {
        private readonly IList<MarketCapInfo> companyPeers;

        private readonly int[] directions = { 1, -1 };

        private readonly bool[] usedDirection = { false, false };

        private readonly int marketCapDictionaryIndex;
        private readonly int maxElements;

        public MarketCapitalizationManager(IList<MarketCapInfo> companyPeers, int marketCapDictionaryIndex)
        {
            this.companyPeers = companyPeers;
            this.marketCapDictionaryIndex = marketCapDictionaryIndex;
            maxElements = this.companyPeers.Count < 5 ? this.companyPeers.Count : 5;
        }

        public RelativePositionInfo GetCompanyPeersInformation(RPCompanyESGComputationResult score)
        {
            var peers = GetCompanyPeers(score);
            var aggregates = ComputeMarketCapitalization(peers);
            return new RelativePositionInfo
            {
                Min = aggregates.Item1,
                Max = aggregates.Item2,
                Peers = PeerOrderingPolicy.GetScores(peers.Select(item => new RPCorporateScore
                {
                    CompanyId = item.Id,
                    CompanyName = item.CompanyName,
                    Score = item.Score
                }), x => x.Score)
            };
        }

        private Tuple<double, double> ComputeMarketCapitalization(ICollection<MarketCapInfo> industryPeers)
        {
            double min = 0;
            double max = 0;

            if (industryPeers != null && industryPeers.Any())
            {
                min = industryPeers.Min(p => p.MarketCap) / 1000;
                max = industryPeers.Max(p => p.MarketCap) / 1000;
            }

            return new Tuple<double, double>(min, max);
        }

        private ICollection<MarketCapInfo> GetCompanyPeers(RPCompanyESGComputationResult focusedRatingsScore)
        {
            byte found = 1;
            byte nbRangesTouched = 0;
            var list = new List<MarketCapInfo>();

            var currentCompany = companyPeers[marketCapDictionaryIndex];
            currentCompany.Score = focusedRatingsScore.OverallPerformance.Score;
            list.Add(currentCompany);

            var offset = 1;

            while (found < maxElements && nbRangesTouched < 2)
            {
                int directionIndex = -1;
                foreach (var direction in directions)
                {
                    directionIndex++;
                    if (!usedDirection[directionIndex])
                    {
                        var newIndex = marketCapDictionaryIndex + (offset * direction);

                        if ((newIndex < 0) || (newIndex >= companyPeers.Count))
                        {
                            usedDirection[directionIndex] = true;
                            nbRangesTouched++;
                            continue;
                        }

                        var marketData = GetCompanyScoreByMarket(newIndex);

                        if (marketData != null)
                        {
                            list.Add(marketData);
                            ++found;
                        }

                        if (found == maxElements)
                        {
                            break;
                        }
                    }

                }
                ++offset;

            }

            return list;
        }

        private MarketCapInfo GetCompanyScoreByMarket(int newIndex)
        {
            var item = companyPeers[newIndex];

            return item.HasEsgResearch ? item : null;
        }
    }
}